package com.junchenrobot.mes.core;

import com.github.rholder.retry.RetryException;
import com.github.rholder.retry.Retryer;
import com.junchenrobot.mes.client.KCClient;
import com.junchenrobot.mes.config.AsyncPool;
import com.junchenrobot.mes.dao.*;
import com.junchenrobot.mes.domain.AgvWork;
import com.junchenrobot.mes.domain.WinderTask;
import com.junchenrobot.mes.domain.WinderTaskRun;
import com.junchenrobot.mes.domain.WinderTaskSpare;
import com.junchenrobot.mes.dto.AgvWorkInfoDto;
import com.junchenrobot.mes.enums.ExecuteStateEnum;
import com.junchenrobot.mes.enums.PoolStateEnum;
import com.junchenrobot.mes.exceptions.TaskNotFoundException;
import com.junchenrobot.mes.exceptions.TaskRunningException;
import com.junchenrobot.mes.listener.source.WinderTaskRedisRepository;
import com.junchenrobot.mes.response.BaseResponse;
import com.junchenrobot.mes.response.impl.RcsResponse;
import com.junchenrobot.mes.vo.param.TaskStateParam;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

/**
 * 任务管理
 *
 * @author SeaWave
 * @date 2023/01/05
 */
@Slf4j
@Component
public class TaskManagment {

    private final WinderDao winderDao;

    private final WinderTaskDao winderTaskDao;

    private final AgvWorkDao agvWorkDao;

    private final AsyncPlcConnector plcConnector;

    private final TaskExecutorCenter taskExecutorCenter;

    private final TaskScheduled taskScheduled;

    private final KCClient kcClient;

    private final DeviceDao deviceDao;

    private final TaskStored stored;

    private final WinderTaskRunDao winderTaskRunDao;

    @Autowired
    public TaskManagment(WinderDao winderDao, WinderTaskDao winderTaskDao, AgvWorkDao agvWorkDao,
                         AsyncPlcConnector plcConnector, TaskExecutorCenter taskExecutorCenter, TaskScheduled taskScheduled,
                         KCClient kcClient, DeviceDao deviceDao, TaskStored stored, WinderTaskRunDao winderTaskRunDao) {
        this.winderDao = winderDao;
        this.winderTaskDao = winderTaskDao;
        this.agvWorkDao = agvWorkDao;
        this.plcConnector = plcConnector;
        this.taskExecutorCenter = taskExecutorCenter;
        this.taskScheduled = taskScheduled;
        this.kcClient = kcClient;
        this.deviceDao = deviceDao;
        this.stored = stored;
        this.winderTaskRunDao = winderTaskRunDao;
    }

    @Autowired
    WinderTaskRedisRepository winderTaskRedisRepository;

    /**
     * 车到达卷绕机位置执行 异步任务
     * [status = 1 ]
     * 更新本地任务状态
     * 更新AGV作业状态
     * 查看卷绕机是否准备好 定时任务 最长5分钟 5分钟后取消任务
     */
    public void winderReady(String taskCode) {
        // 异步任务执行任务
        CompletableFuture<Void> completableFuture = CompletableFuture.runAsync(() -> {
            // 取消定时
            AsyncPool.cancel(taskCode);
            // 查询作业信息
            AgvWorkInfoDto agvWorkInfo = winderTaskDao.getAgvWorkInfo(taskCode);
            // 作业id
            Long workId = agvWorkInfo.getAgvWorkId();
            // 更新任务信息 [等待取料]
            winderTaskDao.updateTaskByTaskCode(taskCode, ExecuteStateEnum.TASK_LOADING.getState());
            // 更新作业状态为到达位置
            agvWorkDao.updateWorkStatus(workId, 2);
            // 查询卷绕机偏移量
            Integer offset = winderDao.selectOffset(agvWorkInfo.getAgvWorkLine(), agvWorkInfo.getAgvWorkSpinning());
            // 执行查看卷绕机是否准备好
            // 查询AGV状态
            Retryer<Boolean> retry = plcConnector.retry(1L, 5);
            try {
                Boolean call = retry.call(() -> {
                    AgvWork agvWork = agvWorkDao.getAgvWork(workId);
                    return agvWork.getStatus() == 3;
                });
                if (call) {
                    // 获取偏移量
                    plcConnector. winderReady(offset);
                }
            } catch (ExecutionException | RetryException e) {
                log.info("执行重试异常或达到最大重试次数");
                throw new TaskRunningException("执行重试异常或达到最大重试次数");
            }
        });
        //异步完成通知结果
        completableFuture.handle((result, e) -> {
            if (e != null) {
                taskExecutorCenter.updateTaskException(taskCode, 1);
            } else {
                taskExecutorCenter.updateTaskFinished(taskCode, 1);
            }
            return null;
        });
    }

    /**
     * 卷绕机开始推丝 2
     */
    public void winderPush(String taskCode) {
        CompletableFuture<Void> completableFuture = CompletableFuture.runAsync(() -> {
            // 查询作业信息
            AgvWorkInfoDto agvWorkInfo = winderTaskDao.getAgvWorkInfo(taskCode);
            // 查询偏移量
            Integer offset = winderDao.selectOffset(agvWorkInfo.getAgvWorkLine(), agvWorkInfo.getAgvWorkSpinning());
            log.info("偏移量{}", offset);
            // 开始推
            try {
                plcConnector.winderPush(offset);
                plcConnector.winderClear(offset);
            } catch (ExecutionException | RetryException e) {
                log.info("执行重试异常或达到最大重试次数");
                throw new TaskRunningException("执行重试异常或达到最大重试次数");
            }
        });
        //异步完成通知结果
        completableFuture.handle((result, e) -> {
            if (e != null) {
                taskExecutorCenter.updateTaskException(taskCode, 2);
            } else {
                taskExecutorCenter.updateTaskFinished(taskCode, 2);
            }
            return null;
        });
    }

    /**
     * 装载任务结束 3
     */
    public void inputFinished(String taskCode) {
        CompletableFuture<WinderTask> completableFuture = CompletableFuture.supplyAsync(() -> {
            // 查询作业信息
            WinderTask task = winderTaskDao.getTask(taskCode);
            // 删除索引
            stored.removeIndex(task.getTaskWinderId());
            // 更新任务为结束
            agvWorkDao.updateWorkStatus(task.getTaskWinderId(), 5);
            //修改结束时间
            winderTaskDao.updateFinishedTime(LocalDateTime.now(), taskCode);
            //更新为取料完成
            deviceDao.updateDevicePoleStatus(task.getTaskDeviceName(), task.getTaskPoleCode(), PoolStateEnum.COMPLETION_OD_TAKE_UP.getState());
            return task;
        });
        // 生成放料任务
        completableFuture.thenAccept(taskScheduled::scheduleOutputWinderTask);
        //异步完成通知结果
        completableFuture.handle((result, e) -> {
            if (e != null) {
                taskExecutorCenter.updateTaskException(taskCode, 3);
            } else {
                taskExecutorCenter.updateTaskFinished(taskCode, 3);
            }
            return null;
        });
    }

    /**
     * 中转站准备好 4
     */
    public void transferReady(String taskCode) {
        CompletableFuture<Void> completableFuture = CompletableFuture.runAsync(() -> {
            WinderTask task = winderTaskDao.getTask(taskCode);
            List<WinderTask> winderTaskList = winderTaskDao.listTaskConditionOne(task.getTaskDeviceName(),
                    ExecuteStateEnum.TASK_FINISHED.getState(), 2);
            int offset = 0;
            int offset2 = 0;
            if (winderTaskList.size() == 2) {
                task = winderTaskList.get(0);
                WinderTask task2 = winderTaskList.get(1);
                Integer taskPoleCode = task.getTaskPoleCode();
//                   Integer taskWinderSpinningCode = task.getTaskWinderSpinningCode();
//                   String taskWinderLsh = task.getTaskWinderLsh();
//                   Integer taskWinderLine = task.getTaskWinderLine();
                task.setTaskExecuteStatus(ExecuteStateEnum.TASK_UNLOADING.getState());
                winderTaskDao.updateTaskById(task);
                if (taskPoleCode == 1) {
                    offset = 2;
                }
                if (taskPoleCode == 2) {
                    offset = 12;
                }
                Integer taskPoleCode2 = task2.getTaskPoleCode();
//                   Integer taskWinderSpinningCode2 = task2.getTaskWinderSpinningCode();
//                   String taskWinderLsh2 = task2.getTaskWinderLsh();
//                   Integer taskWinderLine2 = task2.getTaskWinderLine();
                task2.setTaskExecuteStatus(ExecuteStateEnum.TASK_UNLOADING.getState());
                winderTaskDao.updateTaskById(task2);
                if (taskPoleCode2 == 1) {
                    offset2 = 2;
                }
                if (taskPoleCode2 == 2) {
                    offset2 = 12;
                }
                try {
                    plcConnector.transferRequest(offset, offset2);
//                       if (task.getTaskExecuteStatus().equals(ExecuteStateEnum.TASK_UNLOADING.getState())&&task2.getTaskExecuteStatus().equals(ExecuteStateEnum.TASK_UNLOADING.getState())) {
//                           plcConnector.transferInfo(offset, taskWinderLine, taskWinderSpinningCode, Integer.parseInt(taskWinderLsh));
//                           plcConnector.transferInfo(offset2, taskWinderLine2, taskWinderSpinningCode2, Integer.parseInt(taskWinderLsh2));
//                       }
                } catch (ExecutionException | RetryException e) {
                    log.info("执行重试异常或达到最大重试次数");
                    throw new TaskRunningException("执行重试异常或达到最大重试次数");
                }
            } else {
                Integer taskPoleCode = task.getTaskPoleCode();
//                   Integer taskWinderSpinningCode = task.getTaskWinderSpinningCode();
//                   String taskWinderLsh = task.getTaskWinderLsh();
//                   Integer taskWinderLine = task.getTaskWinderLine();
                task.setTaskExecuteStatus(ExecuteStateEnum.TASK_UNLOADING.getState());
                winderTaskDao.updateTaskById(task);
                log.info("准备接货");
                if (taskPoleCode == 1) {
                    offset = 2;
                }
                if (taskPoleCode == 2) {
                    offset = 12;
                }
                try {
                    plcConnector.transferRequest(offset, offset2);
//                       WinderTask task1 = winderTaskDao.getTask(taskCode);
//                       if (task1.getTaskExecuteStatus().equals(ExecuteStateEnum.TASK_UNLOADING.getState())) {
//                           plcConnector.transferInfo(offset, taskWinderLine, taskWinderSpinningCode, Integer.parseInt(taskWinderLsh));
//                       }
                } catch (ExecutionException | RetryException e) {
                    log.info("执行重试异常或达到最大重试次数");
                    throw new TaskRunningException("执行重试异常或达到最大重试次数");
                }
            }
        });
        //异步完成通知结果
        completableFuture.handle((result, e) -> {
            if (e != null) {
                taskExecutorCenter.updateTaskException(taskCode, 4);
            } else {
                taskExecutorCenter.updateTaskFinished(taskCode, 4);
            }
            return null;
        });
    }

    /**
     * 转推 5
     */
    public void transferPush(String taskCode) {
        CompletableFuture<Void> completableFuture = CompletableFuture.runAsync(() -> {
            WinderTask task = winderTaskDao.getTask(taskCode);
            List<WinderTask> winderTaskList = winderTaskDao.listTaskConditionOne(task.getTaskDeviceName(),
                    ExecuteStateEnum.TASK_FINISHED.getState(), 2);
            int offset = 0;
            int offset2 = 0;
            if (winderTaskList.size() == 2) {
                offset = 2;
                offset2 = 12;
                try {
                    plcConnector.transferRunning(offset, offset2);
                } catch (ExecutionException | RetryException e) {
                    log.info("执行重试异常或达到最大重试次数");
                    throw new TaskRunningException("执行重试异常或达到最大重试次数");
                }

            } else {
                Integer taskPoleCode = task.getTaskPoleCode();
                if (taskPoleCode == 1) {
                    offset = 2;
                }
                if (taskPoleCode == 2) {
                    offset = 12;
                }
                log.info("正在接货");
                try {
                    plcConnector.transferRunning(offset, offset2);
                } catch (ExecutionException | RetryException e) {
                    log.info("执行重试异常或达到最大重试次数");
                    throw new TaskRunningException("执行重试异常或达到最大重试次数");
                }
            }
        });
        //异步完成通知结果
        completableFuture.handle((result, e) -> {
            if (e != null) {
                taskExecutorCenter.updateTaskException(taskCode, 5);
            } else {
                taskExecutorCenter.updateTaskFinished(taskCode, 5);
            }
            return null;
        });
    }

    /**
     * 输出完成 6
     * 卸载任务完成
     */
    public void outputFinished(List<WinderTask> taskList,String taskCode) {
        WinderTask winderTask1 = taskList.get(0);
        String taskCode1 = winderTask1.getTaskCode();
        CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(() -> {
            if (taskList.size()==2){
                WinderTask winderTask2 = taskList.get(1);
                String taskCode2 = winderTask2.getTaskCode();
                // 杆子编号
                Integer taskPoleCode1 = winderTask1.getTaskPoleCode();
                int offset1 = 0,offset2 = 0;
                if (taskPoleCode1 == 1) {
                    offset1 = 2;
                    offset2=12;
                }else{
                    offset1 = 12;
                    offset2=2;
                }
                try {
                    plcConnector.transferInfo(offset1, winderTask1.getTaskWinderLine(), winderTask1.getTaskWinderSpinningCode(), Integer.parseInt(winderTask1.getTaskWinderLsh()));
                    plcConnector.transferInfo(offset2, winderTask2.getTaskWinderLine(), winderTask2.getTaskWinderSpinningCode(), Integer.parseInt(winderTask2.getTaskWinderLsh()));
                } catch (ExecutionException | RetryException e) {
                    log.info("执行重试异常或达到最大重试次数");
                    throw new TaskRunningException("执行重试异常或达到最大重试次数");
                }
                //修改结束时间
                winderTaskDao.updateFinishedTime(LocalDateTime.now(), taskCode1);
                winderTaskDao.updateFinishedTime(LocalDateTime.now(), taskCode2);
                // 更新结束状态
                winderTaskDao.updateTaskByTaskCode(taskCode1, ExecuteStateEnum.TASK_FINISHED.getState());
                winderTaskDao.updateTaskByTaskCode(taskCode2, ExecuteStateEnum.TASK_FINISHED.getState());
                // 更新空杆状态
                log.info("____修改杆子状态2:设为7___");
                deviceDao.updateDevicePoleStatus(winderTask1.getTaskDeviceName(), winderTask1.getTaskPoleCode(), PoolStateEnum.DISCHARGE_COMPLETED.getState());
                deviceDao.updateDevicePoleStatus(winderTask2.getTaskDeviceName(), winderTask2.getTaskPoleCode(), PoolStateEnum.DISCHARGE_COMPLETED.getState());
                log.info("接货完成");
                try {
                    plcConnector.transferFinished(offset1);
                    plcConnector.transferFinished(offset2);
                } catch (ExecutionException | RetryException e) {
                    log.info("执行重试异常或达到最大重试次数");
                    throw new TaskRunningException("执行重试异常或达到最大重试次数");
                }
                return offset1+offset2;
            }else{
                // 杆子编号
                Integer taskPoleCode = winderTask1.getTaskPoleCode();
                int offset = 0;
                if (taskPoleCode == 1) {
                    offset = 2;
                }
                if (taskPoleCode == 2) {
                    offset = 12;
                }
                try {
                    plcConnector.transferInfo(offset, winderTask1.getTaskWinderLine(), winderTask1.getTaskWinderSpinningCode(), Integer.parseInt(winderTask1.getTaskWinderLsh()));

                } catch (ExecutionException | RetryException e) {
                    log.info("执行重试异常或达到最大重试次数");
                    throw new TaskRunningException("执行重试异常或达到最大重试次数");
                }
                //修改结束时间
                winderTaskDao.updateFinishedTime(LocalDateTime.now(), taskCode1);
                // 更新结束状态
                winderTaskDao.updateTaskByTaskCode(taskCode1, ExecuteStateEnum.TASK_FINISHED.getState());
                // 更新空杆状态
                log.info("____修改杆子状态2:设为7___");
                deviceDao.updateDevicePoleStatus(winderTask1.getTaskDeviceName(), taskPoleCode, PoolStateEnum.DISCHARGE_COMPLETED.getState());
                log.info("接货完成");
                try {
                    plcConnector.transferFinished(offset);
                } catch (ExecutionException | RetryException e) {
                    log.info("执行重试异常或达到最大重试次数");
                    throw new TaskRunningException("执行重试异常或达到最大重试次数");
                }
                return offset;
            }
        });
        completableFuture.handle((result, e) -> {
                if (e != null) {
                    taskExecutorCenter.updateTaskException(taskCode, 6);
                } else {
                    // 更新状态
                    taskExecutorCenter.updateTaskFinished(taskCode, 6);
                    // 清除信号
                    try {
                        // 过5s后清除信号
                        if (result==14){
                            plcConnector.transferClear(2);
                            plcConnector.transferClear(12);
                        }else{
                            plcConnector.transferClear(result);
                        }
                    } catch (ExecutionException | RetryException ex) {
                        log.info("重试失败", ex);
                    }
                }
                return null;
        });
    }

    /**
     * 取消任务 20
     *
     * @param taskCode 任务代码
     */
    public void cancelTask(String taskCode) {
        CompletableFuture<WinderTask> completableFuture = CompletableFuture.supplyAsync(() -> {
            WinderTask task = winderTaskDao.getTask(taskCode);
            // 任务执行完成
            task.setTaskExecuteStatus(ExecuteStateEnum.TASK_FINISHED.getState());
            task.setTaskRemark("自动取消任务");
            task.setDataUpdateTime(null);
            task.setTaskFinishedTime(LocalDateTime.now());
            // 更新结束态
            winderTaskDao.updateTaskById(task);
            // 更新任务取消
            agvWorkDao.updateWorkStatus(task.getTaskWinderId(), 1);
            return task;
        });
        // 取消任务
        completableFuture.thenAccept(result -> {
            kcClient.pauseRunningTask(taskCode);
            kcClient.cancelRunningTask(taskCode);
            String taskDeviceName = result.getTaskDeviceName();
            AsyncPool.cancel(taskCode);
            Integer offset = winderDao.selectOffset(result.getTaskWinderLine(), result.getTaskWinderSpinningCode());
            // 取消任务
            WinderTask winderTask = winderTaskDao.getTask(taskCode);
            WinderTaskRun task1 = winderTaskRunDao.getTaskRun(taskCode);
            Integer taskPoleCode1 = winderTask.getTaskPoleCode();
            WinderTaskRun winderTaskRun = WinderTaskRun.builder().build();
            BeanUtils.copyProperties(winderTask, winderTaskRun);
            List<WinderTaskRun> winderTaskRuns = winderTaskRunDao.listUnFinishedTask();
            log.info("20  小车删除前winderTaskRuns:{}", winderTaskRuns.size());
            winderTaskRunDao.deleteWinderTask(task1);
            winderTaskRuns = winderTaskRunDao.listUnFinishedTask();
            log.info("20  小车删除后winderTaskRuns:{}", winderTaskRuns.size());
            Integer taskType = winderTask.getTaskType();
            if (taskType == 1) {//取料
                deviceDao.updateDevicePoleStatus(winderTask.getTaskDeviceName(), winderTask.getTaskPoleCode(), PoolStateEnum.FEED_FAILURE.getState());
            } else {
                deviceDao.updateDevicePoleStatus(winderTask.getTaskDeviceName(), winderTask.getTaskPoleCode(), PoolStateEnum.COMPLETION_OF_TAKE_UP.getState());
            }
            winderTaskDao.deleteWinderTask(winderTask);
            try {
                plcConnector.winderClear(offset);
                log.info("取消确认 清除信息");
            } catch (ExecutionException | RetryException e) {
                log.info("执行重试异常或达到最大重试次数");
                throw new TaskRunningException("执行重试异常或达到最大重试次数");
            }
            kcClient.resetDevice(taskDeviceName);
        });
        //异步完成通知结果
        completableFuture.handle((result, e) -> {
            if (e != null) {
                taskExecutorCenter.updateTaskException(taskCode, 7);
            } else {
                taskExecutorCenter.updateTaskFinished(taskCode, 7);
            }
            return null;
        });
    }

    /**
     * 修改大门状态
     *
     * @param action
     */
    public void modifiedGate(Integer action, String resourceID, Integer state) {
        CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(() -> {
            int offset = 0;
            if (resourceID.equals("1")) {//防火门1
                offset = 22;
            }
            if (resourceID.equals("2")) {//防火门2
                offset = 32;
            }
            if (action == 1) {//开门操作
                try {
                    log.info("开门操作");
                    plcConnector.openTheDoor(offset);
                    log.info("开门");
                } catch (ExecutionException | RetryException e) {
                    log.info("执行重试异常或达到最大重试次数");
                    throw new TaskRunningException("执行重试异常或达到最大重试次数");
                }
            } else {//关门操作
                try {
                    plcConnector.closeTheDoor(offset);
                    log.info("关门");
                } catch (ExecutionException | RetryException e) {
                    log.info("执行重试异常或达到最大重试次数");
                    throw new TaskRunningException("执行重试异常或达到最大重试次数");
                }
            }
            return offset;
        });
        completableFuture.handle((result, e) -> {
            if (e != null) {
                taskExecutorCenter.removeTask(resourceID);
            } else {
                taskExecutorCenter.updateTaskFinished(resourceID, state);
            }
            return null;
        });
    }

}

